package org.springblade.modules.mes.action;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.utils.FuncUtil;
import org.springblade.modules.opcua.bo.OpcValueBO;
import org.springblade.modules.opcua.kit.WorkCache;
import org.springblade.modules.opcua.model.OpcTargetBean;

import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.*;
import java.util.*;
import java.util.Date;

@Slf4j
public class JhSqlServerTaker implements Runnable {

    private OpcTargetBean configBean;


    private Map<String, Object> dataMap;

    public JhSqlServerTaker(OpcTargetBean inBean, Map<String, Object> inDataMap) {
        this.configBean = inBean;
        this.dataMap = inDataMap;
    }


    @Override
    public void run() {
        Long start = System.currentTimeMillis();
        PreparedStatement ps = null;
        try {
            //现有数据
            if (dataMap.size() <= 0) {
                return;
            }
            //数据库连接

            Connection conn = WorkCache.getConn(configBean);
            if (conn == null) {
                throw new Exception("取得数据连接：" + configBean.getId() + "失败");
            }
            //表名称
            String tableName = configBean.getSaveTable();
            if (!FuncUtil.isEmpty(configBean.getSaveScope())) {
                //TODO 分表
            }
            //格式化数据，初始化表
            Map<String, Object> dataNewMap = formatDataAndResetTable(conn, dataMap, tableName);

            //构建插入SQL
            StringBuilder sql = new StringBuilder();
            sql.append(" insert into ").append(tableName).append("( id,head_id,station,collect_time");
            List<String> columns = new ArrayList<>(dataNewMap.keySet());
            for (String column : columns) {
                sql.append(",").append(column);
            }
            sql.append(") values ( ?,?,?,? ");
            for (String column : columns) {
                sql.append(", ?");
            }
            sql.append(")");
            //添加插入参数
//            System.out.println(sql.toString());
            ps = conn.prepareStatement(sql.toString());
            ps.setObject(1, IdUtil.getSnowflake(1, 2).nextId());
            ps.setObject(2, configBean.getId());
            ps.setObject(3, configBean.getOpcName());
            ps.setObject(4, new Date());
            String column;
            Object value;
            for (int i = 0; i < columns.size(); i++) {
                column = columns.get(i);
                value = dataNewMap.get(column);
                ps.setObject(i + 5, value);

            }
            //执行
            ps.execute();
            //发送数据
            List<Map<String, Object>> sendDataList = new ArrayList<>();
            try {
                Map<String, Object> sendDataMap = new HashMap<>();
                sendDataMap.put("headId", configBean.getId());
                sendDataMap.put("station", configBean.getOpcName());
                for (Map.Entry<String, Object> entry : dataNewMap.entrySet()) {
                    sendDataMap.put(StrUtil.toCamelCase(entry.getKey()), entry.getValue());
                }
                sendDataList.add(sendDataMap);

                URL url = new URL(configBean.getTriggerUrl());
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestMethod("POST");
                urlConnection.setDoOutput(true);
                urlConnection.setConnectTimeout(1500);
                // 设置请求头，如Content-Type
                urlConnection.setRequestProperty("Content-Type", "application/json");

                // 写入POST数据
                String postData = JSONUtil.toJsonStr(sendDataList); // 替换为你的POST数据
                byte[] outputInBytes = postData.getBytes("UTF-8");

                OutputStream os = urlConnection.getOutputStream();
                os.write(outputInBytes);
                os.close();

                // 获取响应码
                int responseCode = urlConnection.getResponseCode();
//                System.out.println("POST Response Code :: " + responseCode);

                if (responseCode == HttpURLConnection.HTTP_OK) { // 成功响应
                    // 处理响应
//                    System.out.println("response:\r\n" + urlConnection.getResponseMessage());
                    log.info("*********\r\n{}\r\n{}\r\n{}", configBean.getTriggerUrl(), JSONUtil.toJsonStr(sendDataList), urlConnection.getResponseMessage());
                } else {
                    // 处理错误
//                    System.out.println("response:\r\n" + urlConnection.getResponseMessage());
                    log.info("*********\r\n{}\r\n{}\r\n{}", configBean.getTriggerUrl(), JSONUtil.toJsonStr(sendDataList), urlConnection.getResponseMessage());
                }

                urlConnection.disconnect();

            } catch (Exception ex) {
                log.error("异常*********\r\n发送地址{},\r\n{}，\r\n结果失败：{}", configBean.getTriggerUrl(), JSONUtil.toJsonStr(sendDataList), ex.getMessage());
            } finally {
                // log.error("*********\r\n请求{}\r\n", configBean.getTriggerUrl());
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (ps != null) {
                    ps.close();
                }
            } catch (Exception ex) {

            }
            log.info("保存一条数据耗时：{}", (System.currentTimeMillis() - start));
        }

    }


    /**
     * 格式化数据，同时构建表
     *
     * @param conn
     * @param inDataMap
     * @param tableName
     * @throws Exception
     */
    private Map<String, Object> formatDataAndResetTable(Connection conn, Map<String, Object> inDataMap, String tableName) throws Exception {
        long start = System.currentTimeMillis();
        Statement statement = null;
        ResultSet rs1 = null;
        try {
            //对象
            statement = conn.createStatement();

            //取得表信息
            List<String> columnNameList = WorkCache.getTableInfoCache().get(tableName);
            if (columnNameList == null || columnNameList.size() == 0) {
                synchronized (JhSqlServerTaker.class) {
                    columnNameList = WorkCache.getTableInfoCache().get(tableName);
                    if (columnNameList == null || columnNameList.size() == 0) {
                        //读取表信息，如果表不存在，则创建
                        try {
                            rs1 = statement.executeQuery(" select * from " + tableName);
                        } catch (Exception ex) {
                            statement.execute("CREATE TABLE " + tableName + " (id BIGINT,head_id BIGINT,station nvarchar(100), collect_time datetime,warns nvarchar(1000), PRIMARY KEY(id)) ");
                            rs1 = statement.executeQuery(" select * from " + tableName);
                        }
                        //取得表现在的列
                        ResultSetMetaData resultSetMetaData = rs1.getMetaData();
                        columnNameList = new ArrayList<>();
                        int columnCount = resultSetMetaData.getColumnCount();
                        for (int c = 0; c < columnCount; c++) {
                            columnNameList.add(resultSetMetaData.getColumnName(c + 1));
                        }
                        WorkCache.getTableInfoCache().put(tableName, columnNameList);
                    }
                }
            }


            //前缀长度
            int len = configBean.getIdentifierPreview().length() + 1;
            String key;
            Map<String, String> needToAddColumnMap = new HashMap<>();
            Object nowValue;
            OpcValueBO valueBO;
            //构造格式数据，返回
            Map<String, Object> dataNewMap = new HashMap<>();
            String valueToString;
            List<String> warns = new ArrayList<>();
            for (Map.Entry<String, Object> entry : inDataMap.entrySet()) {
                nowValue = entry.getValue();
                if (nowValue == null) {
                    continue;
                }
                key = entry.getKey().substring(len).toLowerCase();


                //转换
                valueBO = convert(nowValue);

                if (key.startsWith("warn_")) {
                    if (valueBO.getValue() != null) {
                        valueToString = valueBO.getValue().toString();
                        if ("true".equalsIgnoreCase(valueToString) || "1".equals(valueToString)) {
                            warns.add(key.substring(5));
                        }
                    }
                } else {
                    //是否包含，不包含构建创建语句
                    if (!columnNameList.contains(key)) {
                        StringBuilder sql = new StringBuilder("alter table ");
                        sql.append(tableName).append(" add ").append(key).append(" ").append(valueBO.getColumnType()).append(" DEFAULT NULL");
                        needToAddColumnMap.put(key, sql.toString());
                    }
                    dataNewMap.put(key, valueBO.getValue());
                }
            }
            dataNewMap.put("warns", FuncUtil.join(warns));
            //有需要创建的列
            if (needToAddColumnMap.size() > 0) {
                List<String> toAddList = new ArrayList<>(needToAddColumnMap.keySet());
                Collections.sort(toAddList);
                for (String toCol : toAddList) {
                    try {
                        //创建新增列
                        statement.execute(needToAddColumnMap.get(toCol));
                    } catch (Exception ex) {

                    }
                    //新增列添加到计划
                    if (!columnNameList.contains(toCol)) {
                        columnNameList.add(toCol);
                    }

                }
            }
            return dataNewMap;
        } finally {
            try {
                if (rs1 != null) {
                    rs1.close();
                }
            } catch (Exception ex) {

            }
            try {
                if (statement != null) {
                    statement.close();
                }
            } catch (Exception ex) {

            }
            log.info("格式数据，重新构建表，耗时：{}", (System.currentTimeMillis() - start));
        }
    }

    /**
     * 类型转换
     *
     * @param value
     * @return
     */
    public static OpcValueBO convert(Object value) {
        Object newValue;
        String type;
        if (value instanceof Short) {
            newValue = Integer.valueOf((Short) value);
            type = " int ";
        } else if (value instanceof Integer) {
            newValue = (Integer) value;
            type = " int ";
        } else if (value instanceof Long) {
            newValue = (Long) value;
            type = " bigint ";
        } else if (value instanceof Float) {
            newValue = BigDecimal.valueOf((Float) value);
            type = " decimal(18,4) ";
        } else if (value instanceof Double) {
            newValue = BigDecimal.valueOf((Double) value);
            type = " decimal(18,4) ";
        } else if (value instanceof BigDecimal) {
            newValue = (BigDecimal) value;
            type = " decimal(18,4) ";
        } else {
            newValue = value.toString();
            type = " nvarchar(64) ";
        }
        return new OpcValueBO(newValue, type);
    }

}
